#include "../stdafx.h"
#include "Game.h"
#include <iostream>

namespace Model{

	Game::Game()
	{
		TileFactory* tileFactory=new TileFactory();
		this->myGrid.init();
		this->freeTile=static_cast<MobileTile*>(tileFactory->createTile(MOBILE,lineTile));
	}

	Game* Game::clone()
	{
		return NULL;
	}
	/**
	 * Add a color to the game
	 * @param name : the name of the color
	 */
	int Game::addColor(string name)
	{
		int nextAvailableId=0;
		while(this->colors.find(nextAvailableId) != this->colors.end()){
			nextAvailableId++;
		}

		if (nextAvailableId>=NUM_MAX_PLAYER){
			DWRITE("/!\\ An exception is beeing thrown away in ConcreteGamePrototype");
			throw new IllegalOperation("Impossible Operation, Can not register any new Color ");
			
		}
		this->colors.insert(make_pair(nextAvailableId,new Color(name)));
		return (nextAvailableId);
	}
	/**
	 * Initialize the game in function of the number of colors
	 */
	void Game::initGame()
	{
		unsigned int nbPlayer=this->colors.size();
		unsigned int i=0, j=0;
		for(i=0; i<nbPlayer;++i)
		{
			while(j<(myTreasures.size()/(nbPlayer))*(i+1)){
				this->colors[i]->pushTreasure(this->myTreasures[j]);
				j++;
			}
		}
		this->colors[0]->setCurrentTile(this->myGrid.getIterator()->getEc());
	}
	/**
	 * @return the free tile of the game
	 */
	MobileTile* Game::getFreeTile()
	{
		return this->freeTile;
	}
	/**
	 * set the orientation of the free tile
	 * @param ori : the new orientation
	 */
	void Game::setFreeTileOrientation(Orientation ori)
	{
		this->freeTile->setOrientation(ori);
	}
	/**
	 * insert the free tile in the grid by pushing an entire row or column,
	 * the last tile to be pushed become the free tile
	 */
	void Game::pushTile(int tileId, int colorId)
	{
		this->freeTile=this->myGrid.pushTile(this->freeTile, tileId);
		if(this->colors[colorId]->getCurrentTile()==this->freeTile){
			this->colors[colorId]->setCurrentTile(this->myGrid.getPushableTile(tileId));
		}
		this->initIterators();
	}
	/**
	 * deplace a color in a certain direction
	 * @param idColor : the color to deplace
	 * @param dir : the direction
	 */
	void Game::deplaceColor(int idColor, Direction dir)
	{
		switch(dir){
		case UP: this->colors[idColor]->goUp(); break;
		case DOWN: this->colors[idColor]->goDown(); break;
		case LEFT: this->colors[idColor]->goLeft(); break;
		case RIGHT: this->colors[idColor]->goRight(); break;
		}
	}
	/**
	 * Method used when e color deplacment is over, if the treasure on the tile correspond
	 *  to the next treasure of the color, pop the treasure from the treasureStack of the
	 *  color.
	 *  @param idColor : the color id
	 */
	void Game::endDeplacmentColor(int idColor)
	{
		if(this->colors[idColor]->getTopTreasure()==this->colors[idColor]->getCurrentTile()->getTreasure()->getName()){
			this->colors[idColor]->popTreasure();
		}
	}
	/**
	 * @return the id of the winner (-1 if nobody wins)
	 */
	int Game::winner()
	{
		for(int i=0; i<this->colors.size(); ++i){
			if(!(this->colors[i]->hasTreasure())) return i;
		}
		return -1;
	}
	/**
	 * @return an iterator over the grid
	 */
	Grid::GridIterator* Game::getGridIterator()
	{
		Grid::GridIterator* it=this->myGrid.getIterator();
		this->iterators.push_back(it);
		return it;
	}
	/**
	 * initialize all the iterators of the game
	 */
	void Game::initIterators()
	{
		for(int i=0; i<this->iterators.size(); ++i)
		{
			this->iterators[i]->init();
			cout<<"init"<<endl;
		}
	}
	/**
	 * remove all the iterators of the game
	 */
	void Game::removeIterator()
	{
		this->iterators.clear();
	}
	/**
	 * @param id : a color id
	 * @return the color corresponding to the color id
	 */
	Color* Game::getColor(int id)
	{
		if(id<this->colors.size())
			return this->colors[id];
		return NULL;
	}

	Game::~Game(void)
	{
	}
	/**
	 * @param id : the id of a color
	 * remove the color from the game
	 */
	void Game::removeColor(int id){
		this->colors.erase(this->colors.find(id));
}
}
